window.x = new function() {};
x.noop = function() {};
x.generateID = function(str) {
  return (str || '') + '_' + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15)
}

/**
 * 
 * @param {Object} fn
 * @param {Object} when
 * @param {Object} context
 * @param {Object} data
 */
x.later = function(fn, when, context, data) {
  when = when || 0;
  var target = Date.now() + when;
  var m = fn;
  var d = data;
  var f;
  var r;

  if (typeof fn === 'string') {
    m = context[fn];
  }

  f = function() {
    m.apply(context, [].concat(d));
  };
  var recall = function() {
    if (Date.now() > target) {
      f();
    } else {
      r = setTimeout(recall, 0);
    }
  };
  recall();
};

x.waitFor = function(test, complete, timeout, step) {
    var timeout = timeout || 1000;
    var result, start = new Date().getTime()
    var interval = setInterval(function() {
      if ((new Date().getTime() - start < timeout) && !result) {
        result = test()
        if (result != undefined) {
          clearInterval(interval);
          complete(result);
        }
      } else {
        complete(result);
        clearInterval(interval)
      }
    }, step || 20)
  }
  /**
   *
   * @param {Object} obj
   * @param {Object} valueName
   * @param {Object} complete
   * @param {Object} timeout
   * @param {Object} step
   */
x.waitForValue = function(obj, valueName, complete, timeout, step) {
  x.waitFor(function() {
    return obj[valueName];
  }, complete || x.noop());
}